import React, { useRef, useState, useCallback, useEffect } from 'react';
// 1、虚拟列表
// 其核心思想就是在处理用户滚动时，只改变列表在可视区域的渲染部分，具体步骤为：
// 先计算可见区域起始数据的索引值startIndex和当前可见区域结束数据的索引值endIndex，假如元素的高度是固定的，那么startIndex的算法很简单
// 上述的操作可以总结成五步：
// 不把长列表数据一次性全部直接渲染在页面上
// 截取长列表一部分数据用来填充可视区域
// 长列表数据不可视部分使用空白占位填充（下图中的startOffset和endOffset区域）
// 监听滚动事件根据滚动位置动态改变可视列表
// 监听滚动事件根据滚动位置动态改变空白填充
// 2懒加载
// 对于长列表渲染，传统的方法是使用懒加载的方式，下拉到底部获取新的内容加载进来，其实就相当于是在垂直方向上的分页叠加功能。
// 3、时间分片
// requestAnimationFrame +fragment
// requestAnimationFrame也是个定时器，不同于setTimeout，它的时间不需要我们人为指定，这个时间取决于当前电脑的刷新率，如果是 60Hz ，那么就是 16.7ms 执行一次，如果是 120Hz 那就是 8.3ms 执行一次
// 因此requestAnimationFrame也是个宏任务

// 计算容器总高度
const getTotalHeight = (rowCount, rowHeight) => rowCount * rowHeight;

const VirtualScroll = ({ rowCount, rowHeight, renderRow }) => {
  const containerRef = useRef(null);
  const [startIndex, setStartIndex] = useState(0);
  const [endIndex, setEndIndex] = useState(5);

  // 计算可视区域内的开始和结束索引
  const updateVisibleRows = useCallback(() => {
    if (containerRef.current) {
      const containerHeight = containerRef.current.clientHeight;
      const scrollTop = containerRef.current.scrollTop;

      const startIndex = Math.floor(scrollTop / rowHeight);
      const endIndex = Math.min(rowCount - 1, Math.ceil((scrollTop + containerHeight) / rowHeight));

      setStartIndex(startIndex);
      setEndIndex(endIndex < 5 ? 5 : endIndex); // 至少渲染5行
    }
  }, [rowCount, rowHeight]);

  // 更新可视区域内的行
  useEffect(() => {
    updateVisibleRows();
    window?.addEventListener('resize', updateVisibleRows);
    if (containerRef && containerRef?.current) {
      containerRef?.current.addEventListener('scroll', updateVisibleRows);
    }
    return () => {
      window?.removeEventListener('resize', updateVisibleRows);
      if (containerRef && containerRef?.current) {
        containerRef?.current.removeEventListener('scroll', updateVisibleRows);
      }
    };
  }, [updateVisibleRows]);

  // 生成可视区域内的行
  const rows = [];
  for (let i = startIndex; i <= endIndex; i++) {
    rows.push(renderRow(i));
  }

  return (
    <div
      ref={containerRef}
      style={{
        height: 128, // 可视区域的高度
        overflowY: rowCount < 6 ? 'hidden' : 'auto',
        position: 'relative',
      }}
    >
      <div
        style={{
          height: getTotalHeight(rowCount, rowHeight),
          position: 'relative',
        }}
      >
        <div
          style={{
            position: 'absolute',
            top: startIndex * rowHeight,
            width: '100%',
          }}
        >
          {rows}
        </div>
      </div>
    </div>
  );
};

export default VirtualScroll;
